Skip to content

Fix E2E chat test timeout: move E2E tests to local Docker pre-push workflow, add WebGPU/Vulkan support - #68

Merged
devlux76 merged 4 commits into
mainfrom
copilot/fix-e2e-test-timeout
Mar 21, 2026
Merged

Fix E2E chat test timeout: move E2E tests to local Docker pre-push workflow, add WebGPU/Vulkan support#68
devlux76 merged 4 commits into
mainfrom
copilot/fix-e2e-test-timeout

Conversation

Copilot AI commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

chat.spec.ts and model-loading.spec.ts timed out in CI because onnx-community/Qwen3.5-0.8B-ONNX (~400 MB q4) is too large to download and run on WASM within the 8-minute window on a CPU-only ubuntu-latest runner — the only available backend in that environment. GitHub Actions Pro does not offer GPU-enabled runners, so E2E tests are moved to a local Docker pre-push workflow instead of CI.

Local Docker E2E runner

A new e2e/Dockerfile builds on the official Playwright Jammy image and layers Mesa Vulkan drivers on top for Intel/AMD GPU support:

  • Intel ANV and AMD RADV via /dev/dri passthrough (hardware WebGPU)
  • lavapipe as an unconditional software-Vulkan fallback (no GPU hardware required)

e2e/run-local.sh orchestrates the run:

  • Builds the Docker image on first run (~3 min, then cached)
  • Detects /dev/dri and passes it to the container for real GPU access; falls back to lavapipe automatically
  • Caches node_modules in a named Docker volume (q2-e2e-node-modules) for fast subsequent runs
  • Sets E2E_GPU_AVAILABLE=1 only when /dev/dri is actually present, so playwright.config.ts uses hardware GL vs. SwiftShader correctly

Pre-push git hook

.husky/pre-push runs bun run test:e2e:local automatically before every git push. It skips gracefully if Docker is not installed and can be bypassed with git push --no-verify.

package.json script

A new test:e2e:local script (bash e2e/run-local.sh) is the single entry point for running E2E tests locally.

CI change

The e2e job is removed from .github/workflows/ci.yml. A comment block explains where E2E tests now live and how to run them.

Conditional SwiftShader / hardware GL

--use-gl=swiftshader is included only when E2E_GPU_AVAILABLE is unset, so systems with a real GPU use hardware Vulkan/ANGLE and systems without fall back to Mesa software rendering:

const gpuArgs = [
  '--enable-gpu',
  '--ignore-gpu-blocklist',
  '--enable-unsafe-webgpu',
  '--disable-gpu-sandbox',
  // SwiftShader when no GPU is available; dropped when E2E_GPU_AVAILABLE=1
  ...( process.env.E2E_GPU_AVAILABLE ? [] : ['--use-gl=swiftshader'] ),
];

E2E_DTYPE env var

Both chat.spec.ts and model-loading.spec.ts read process.env.E2E_DTYPE ?? 'q4' for the dtype selection, parallel to the existing E2E_MODEL override.

Original prompt

This section details on the original issue you should resolve

<issue_title>Error in E2E tests</issue_title>
<issue_description>The E2E pipeline is failing:

1) [chromium] › e2e/chat.spec.ts:18:3 › Real chat interaction › sends a message and receives a streamed response 

    Test timeout of 480000ms exceeded.

    Error: page.click: Test timeout of 480000ms exceeded.
```</issue_description>

<agent_instructions>Latest iteration of a long list of failures, but this is progress because the CI pipeline caught it. By the way, make sure we're launching a GPU  worker to run these on. I have a theory that transformers can't run a lot of these models in wasm. If so it would explain a lot.  In any event, please solve the issue, run the full pipeline, take screenshots of it passing, it fails log it and keep working it until it's resolved. These failures are valuable information for the future to know what to do better next time.   Thanks!</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Copilot AI changed the title [WIP] Fix error in E2E tests for chat interaction Fix E2E chat test timeout: swap CI model, add WebGPU flags, add E2E_DTYPE override Mar 20, 2026
Copilot AI requested a review from devlux76 March 20, 2026 22:29
@devlux76

Copy link
Copy Markdown
Owner

@copilot I agree with what you said here, "chat.spec.ts and model-loading.spec.ts timed out in CI because onnx-community/Qwen3.5-0.8B-ONNX (~400 MB q4) is too large to download and run on WASM within the 8-minute window on a CPU-only ubuntu-latest runner — the only available backend in that environment."

What do we need to change to get a GPU runner in there, otherwise we're going to spend a lot of money on CPU time when when we could spend a lot less on GPU time and not be bottle necked here.

We can't be the only ones testing WebGPU apps E2E in a pipeline like this. I'll bet theres even a specific runner for this that would save us some time on our setup not just testing.

…, three-tier CI docs

Co-authored-by: devlux76 <86517969+devlux76@users.noreply.github.com>
Agent-Logs-Url: https://github.com/devlux76/q2/sessions/0dbd6e2c-0b47-4820-b874-7734ab896901

Copilot AI commented Mar 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot I agree with what you said here, "chat.spec.ts and model-loading.spec.ts timed out in CI because onnx-community/Qwen3.5-0.8B-ONNX (~400 MB q4) is too large to download and run on WASM within...

Done in commit 96b2b31. Here's how it works now — no workflow edits needed to upgrade runners:

ci.ymlruns-on is now driven by a repo variable:

runs-on: ${{ vars.E2E_RUNNER || 'ubuntu-latest' }}

Set E2E_RUNNER in Settings → Secrets and variables → Actions → Variables once and every future run picks it up.

Three tiers are documented in the workflow comments:

Tier E2E_RUNNER repo var E2E_GPU_AVAILABLE Model Notes
1 — CPU/free (default) (unset) (unset) SmolLM2-135M SwiftShader, WASM
2 — GitHub-hosted GPU ubuntu-latest-gpu 1 Qwen3.5-0.8B NVIDIA T4 via org runner group (Teams/Enterprise)
3 — Self-hosted GPU your runner label 1 Qwen3.5-0.8B any NVIDIA runner you register

playwright.config.ts--use-gl=swiftshader is now conditional:

...( process.env.E2E_GPU_AVAILABLE ? [] : ['--use-gl=swiftshader'] ),

On CPU runners it forces Mesa software GL (always works). On GPU runners (E2E_GPU_AVAILABLE=1) it's dropped so Chrome uses the real hardware Vulkan/ANGLE path and WebGPU gets full GPU throughput.

E2E_MODEL, E2E_DTYPE, and E2E_GPU_AVAILABLE are all repo-variable-driven the same way, so upgrading from Tier 1 to Tier 2/3 is purely a Settings change — no code to touch.

Copilot AI changed the title Fix E2E chat test timeout: swap CI model, add WebGPU flags, add E2E_DTYPE override Fix E2E chat test timeout: swap CI model, add WebGPU flags, add E2E_DTYPE override, add GPU runner support Mar 20, 2026

@devlux76 devlux76 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work!

@devlux76

Copy link
Copy Markdown
Owner

@copilot As it turns out this was sort of a mistake. GitHub does not offer GPU instance instances on Pro as far as I can tell. It seems these are only available on Enterpriise which I cannot afford. What we can do is to create a docker container and run it locally and make it part of the precommit hook. This docket container should have Vulkan since my own system is Intel/AMD. I'll just have it run locally before committing.

So thank you for your work, but we need to move e2e back to the laptop. A docker container with vulkan and playwright is likely the best solution. I'd go with a self hosted runner, but after investigating further this cannot be made secure. What can be made secure is local e2e testing before pushing as part of the bun run build, bun run test locally.

Thank you for your hardwork. Please just get this part right (remove e2e in CI and place it locally) and I think we're complete on the entire issue.

Copilot AI commented Mar 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot As it turns out this was sort of a mistake. GitHub does not offer GPU instance instances on Pro as far as I can tell. It seems these are only available on Enterpriise which I cannot afford. ...

Done in commit ba01c92. E2E tests are now fully local — removed from CI, wired into a pre-push hook via Docker.

What changed:

e2e/Dockerfile — builds on the official Playwright Jammy image and layers Mesa Vulkan on top:

  • Intel ANV and AMD RADV via /dev/dri passthrough (hardware WebGPU)
  • lavapipe as an automatic software-Vulkan fallback (no GPU needed)

e2e/run-local.sh — the run script:

  • Builds the Docker image on first run (~3 min, then cached)
  • Detects /dev/dri and passes it to the container — so your Intel/AMD system gets real hardware Vulkan/WebGPU automatically
  • Caches node_modules in a named Docker volume (q2-e2e-node-modules) so bun install is fast on re-runs
  • Sets E2E_GPU_AVAILABLE=1 only when /dev/dri is actually present

.husky/pre-push — new hook that runs bun run test:e2e:local before every git push. Skips gracefully if Docker isn't installed. Override anytime with git push --no-verify.

package.json — new test:e2e:local script (calls the run script above).

ci.ymle2e job removed; replaced with a comment pointing to e2e/Dockerfile and e2e/run-local.sh.

To run manually: bun run test:e2e:local
To rebuild the Docker image: docker build -t q2-e2e -f e2e/Dockerfile .

Copilot AI changed the title Fix E2E chat test timeout: swap CI model, add WebGPU flags, add E2E_DTYPE override, add GPU runner support Fix E2E chat test timeout: move E2E tests to local Docker pre-push workflow, add WebGPU/Vulkan support Mar 21, 2026
Copilot AI requested a review from devlux76 March 21, 2026 01:09
@devlux76
devlux76 marked this pull request as ready for review March 21, 2026 03:31
Copilot AI review requested due to automatic review settings March 21, 2026 03:31
@devlux76
devlux76 merged commit 0909ef7 into main Mar 21, 2026
3 checks passed
@devlux76
devlux76 deleted the copilot/fix-e2e-test-timeout branch March 21, 2026 03:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR moves Playwright E2E coverage out of GitHub Actions (where CPU-only runners time out on large models) and into a local Docker-based workflow that can use WebGPU/Vulkan when available, while also adding env-driven model dtype overrides for the E2E specs.

Changes:

  • Removed the e2e job from CI and documented the new local E2E execution path.
  • Added a Docker-based local E2E runner (e2e/Dockerfile, e2e/run-local.sh) and wired it into package.json plus a .husky/pre-push hook.
  • Updated E2E specs to support E2E_DTYPE overrides and updated Playwright Chromium launch args to support WebGPU.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
playwright.config.ts Adds Chromium launch args intended to enable WebGPU and select software vs hardware paths.
package.json Adds test:e2e:local script as the entry point for Docker-based E2E runs.
e2e/run-local.sh New Docker orchestration script for local Playwright runs with optional /dev/dri passthrough.
e2e/model-loading.spec.ts Adds E2E_DTYPE support for selecting model dtype during the loading test.
e2e/chat.spec.ts Adds E2E_DTYPE support for selecting model dtype during the chat test.
e2e/Dockerfile New local E2E image (Playwright base + Mesa Vulkan drivers + Bun).
.husky/pre-push Runs the local Docker E2E suite before git push (skips when Docker is absent).
.github/workflows/ci.yml Removes CI E2E job and adds guidance for running E2E locally.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread e2e/run-local.sh
Comment on lines +50 to +61
# ── Run tests ─────────────────────────────────────────────────────────────
echo "▶ Running E2E tests..."
exec docker run --rm \
--ipc=host \
${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \
-v "$REPO_ROOT:/app" \
-v "$NM_VOLUME:/app/node_modules" \
-w /app \
-e CI=true \
-e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \
-e E2E_MODEL="${E2E_MODEL:-}" \
-e E2E_DTYPE="${E2E_DTYPE:-}" \

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run-local.sh always injects E2E_MODEL/E2E_DTYPE into the container, even when they’re unset on the host (they become empty strings). Because the specs use nullish coalescing (??), an empty string prevents the defaults from being applied and selectOption/model id filling can fail. Only pass these -e flags when the vars are non-empty, or pass explicit defaults (e.g., omit the env vars unless set).

Suggested change
# ── Run tests ─────────────────────────────────────────────────────────────
echo "▶ Running E2E tests..."
exec docker run --rm \
--ipc=host \
${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \
-v "$REPO_ROOT:/app" \
-v "$NM_VOLUME:/app/node_modules" \
-w /app \
-e CI=true \
-e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \
-e E2E_MODEL="${E2E_MODEL:-}" \
-e E2E_DTYPE="${E2E_DTYPE:-}" \
# ── Optional E2E env flags ────────────────────────────────────────────────
E2E_FLAGS=()
if [ -n "${E2E_MODEL:-}" ]; then
E2E_FLAGS+=(-e "E2E_MODEL=$E2E_MODEL")
fi
if [ -n "${E2E_DTYPE:-}" ]; then
E2E_FLAGS+=(-e "E2E_DTYPE=$E2E_DTYPE")
fi
# ── Run tests ─────────────────────────────────────────────────────────────
echo "▶ Running E2E tests..."
exec docker run --rm \
--ipc=host \
${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \
${E2E_FLAGS[@]+"${E2E_FLAGS[@]}"} \
-v "$REPO_ROOT:/app" \
-v "$NM_VOLUME:/app/node_modules" \
-w /app \
-e CI=true \
-e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \

Copilot uses AI. Check for mistakes.
Comment thread e2e/chat.spec.ts
Comment on lines 15 to +16
const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4';

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process.env.E2E_MODEL ?? ... / process.env.E2E_DTYPE ?? ... will treat an empty string as a valid override. With the new Docker runner currently passing empty env vars, this can result in MODEL_ID/MODEL_DTYPE being '' and the test failing. Prefer || (or a small normalization helper) so empty strings fall back to defaults.

Suggested change
const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4';
const MODEL_ID = process.env.E2E_MODEL || 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE || 'q4';

Copilot uses AI. Check for mistakes.
Comment thread e2e/model-loading.spec.ts
Comment on lines 17 to +18
const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4';

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in chat.spec.ts: using ?? here will not fall back when E2E_MODEL/E2E_DTYPE are present but empty (which the new Docker runner currently does). Use || (or normalize env vars) so empty values don’t break model selection.

Suggested change
const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4';
const MODEL_ID = process.env.E2E_MODEL || 'onnx-community/Qwen3.5-0.8B-ONNX';
const MODEL_DTYPE = process.env.E2E_DTYPE || 'q4';

Copilot uses AI. Check for mistakes.
Comment thread e2e/model-loading.spec.ts
*
* The default model is onnx-community/Qwen3.5-0.8B-ONNX (q4). Override with
* the E2E_MODEL environment variable for faster CI runs.
* the E2E_MODEL and E2E_DTYPE environment variables for faster CI runs.

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment still says the env vars are for “faster CI runs”, but this PR removes E2E from CI. Consider updating the wording to “faster local runs” (or similar) to avoid misleading guidance.

Suggested change
* the E2E_MODEL and E2E_DTYPE environment variables for faster CI runs.
* the E2E_MODEL and E2E_DTYPE environment variables for faster local runs.

Copilot uses AI. Check for mistakes.
Comment thread e2e/Dockerfile
#
# Update this tag when you bump @playwright/test in package.json.
# Available tags: https://mcr.microsoft.com/v2/playwright/tags/list
FROM mcr.microsoft.com/playwright:v1.50.1-jammy

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Playwright base image version (v1.50.1-jammy) is far behind the repo’s @playwright/test version (currently ^1.58.2). Version mismatches between the runner and the preinstalled browsers/drivers can cause flaky or broken E2E runs. Update the image tag to match the Playwright version used by the repo (and consider pinning playwright/@playwright/test consistently).

Suggested change
FROM mcr.microsoft.com/playwright:v1.50.1-jammy
FROM mcr.microsoft.com/playwright:v1.58.2-jammy

Copilot uses AI. Check for mistakes.
Comment thread playwright.config.ts
Comment on lines +19 to +21
* Without GPU (lavapipe fallback):
* --use-gl=swiftshader forces the Mesa software Vulkan rasterizer.
* WebGPU still works; inference falls back to WASM.

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment claims --use-gl=swiftshader “forces the Mesa software Vulkan rasterizer (lavapipe)”, but SwiftShader is Chromium’s software GL backend and is distinct from Mesa’s Vulkan lavapipe. This is likely to confuse future debugging of WebGPU/Vulkan issues; please adjust the comment to describe the actual fallback(s) being used.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error in E2E tests

3 participants